
## 中间件原理

所谓中间件，就是一个函数：
```javascript
function mw(req,res,next){
    // do sth 
    // to next() or not
}
```

## 路由定义文件

所谓路由定义文件，就是一个`Node.js`模块，该模块导出一系列路由定义和它们要挂载到的地址。例如：
```javascript
const routes={
    'add':{
        method:'post',
        path:'/add',
        middlewares:[jsonMiddleware,add],
    },
    'edit':{
        method:'post',
        path:'/edit',
        middlewares:[jsonMiddleware,edit],
    },
};

module.exports={
    mount:'/base',
    routes,
};
```

注意：
1. 路由文件包括一个 `路由挂载点` 和 若干个 `路由定义` 组成。每一个 `路由定义` 都表示当相应的方法、路径满足时应该执行的一系列中间件函数。
2. 路由文件名和其中的每一条 `路由定义名` 都能构成一条 `资源名` 。
3. 每次用户通过浏览器访问相关`URL`，服务端最终都只会配到一条唯一的 `路由定义` ，然后服务端会执行与`路由定义`相关联的一系列`中间件`。
4. 尽管`路由文件名`和其中的一条`路由定义名`都会对应到某一条`资源名`，但并不是每个`资源名`都是能对应到具体的一条路由。为了表达层级的概念，可以用路由文件名+后缀的方式来表示层级式的资源概念。比如`<resource_module_name>?`表达了特定模块下的某资源名的概念，这在提供层级式菜单管理时会有用。

## 权限检查

我们说，每次用户访问，都会而且只会唯一命中一条`路由定义`。当一条`路由定义`被命中时，`Skeleton`会根据对应的资源名，判断是否需要权限检查。
* 对于一些资源，比如用户登陆模块、用户注册模块、系统安装模块等，永远无需权限检查。
* 对于其他资源，如果确需权限检查，则会先进行数据库查询，检测当前用户的角色是否能满足相关权限，然后才视检查结构决定是否去执行相关中间件。

这是怎么做到的呢？在对每一条`路由定义`进行注册的时候，都会进行以下操作：
```javascript
// 当前路由定义所对应的方法、路径、和中间件
const {method,path,middlewares}=route;
// 当前路由定义所对应的资源名
const resourceName= //... ;

// 创建授权检查中间件
const authorizationMw=interceptor.requireTrue(req=>{
    // 如果是超级用户
    if(req.session.userid==1){ return Promise.resolve(true); }
    // ...否则，根据当前资源名和当前用户角色进行权限检查
});
// 安装、登陆、登出、注册等模块的访问无身份限制
if(!shouldPassBy(resourceName)){ middlewares.unshift(authorizationMw); }

// ...依次注册 middlewares 中的这些中间件函数到路由器即可
```

需要注意的是，很多路由定义种包含了`allowRoles=[]`的配置，这会让系统安装的时候将相关资源与角色的配置关系写入数据库，如果不提供这个配置，则默认在系统安装时创建允许匿名访问、允许普通用户访问的配置关系，安装完成后，可以通过后台管理界面对相关资源和角色的配置关系进行调整。